#include "VONode.h"
#include <algorithm>



VONode::VONode(Vector3d minimum,Vector3d maximum) : minv(minimum),maxv(maximum),cube(minv,(maxv-minv).x)
{
	for(int i = 0;i < 8;i++)
		data[i] = 0;
	medv = (minv+maxv)/2;
	size = (int)(medv.x - minv.x);

	//f << "VONode created " << minv.print() << " " << medv.print() <<" " << maxv.print() << "\n";
}


VONode::~VONode(void)
{
	delete[] data;
}


void VONode::set(int x,int y,int z)
{
	if(size == 0)
	{
		//f << "\n";
		return;
	}
	if( x < medv.x)
	{
		if(y < medv.y)
		{
			if(z < medv.z)
			{
				create(0,0,0,0);
				data[0]->set(x,y,z);
			}
			else
			{
				create(1,0,0,1);
				data[1]->set(x,y,z);
			}
		}
		else
		{
			if(z < medv.z)
			{
				create(2,0,1,0);
				data[2]->set(x,y,z);
			}
			else
			{
				create(3,0,1,1);
				data[3]->set(x,y,z);
			}
		}
	}
	else
	{
		if(y < medv.y)
		{
			if(z < medv.z)
			{
				create(4,1,0,0);
				data[4]->set(x,y,z);
			}
			else
			{
				create(5,1,0,1);
				data[5]->set(x,y,z);
			}
		}
		else
		{
			if(z < medv.z)
			{
				create(6,1,1,0);
				data[6]->set(x,y,z);
			}
			else
			{
				create(7,1,1,1);
				data[7]->set(x,y,z);
			}
		}

	}
}

bool VONode::empty()
{
	for(int i = 0;i < 8;i++)
	{
		if(data[i] != 0)
			return false;
	}
	return true;
}

TraceResult VONode::hit(const Ray &ray)
{
	TraceResult closest = cube.collision(ray);
	if(size == 0)
		return closest;

	//if starts inside, it hits for sure

	if(!closest.hit)
	{
		if(!(ray.position.x > minv.x && ray.position.y > minv.y && ray.position.z > minv.z &&
			ray.position.x < maxv.x && ray.position.y < maxv.y && ray.position.z < maxv.z))
			return closest;

	}

	closest = TraceResult::empty;


	for(int i = 0;i < 8;i++)
	{
		if(data[i] != 0)
		{
			TraceResult tr = data[i]->hit(ray);
			if(tr.hit && tr.distance < closest.distance && tr.distance > 0.001)
			{
				closest = tr;
			}
		}
	}
	return closest;
}